package br.com.cedente.http;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.Scanner;
import java.util.TreeMap;

import org.apache.commons.io.FilenameUtils;

import br.com.cedente.log.RegistroDeLog;
import br.com.sicoob.model.IndiceDeDados;

/**
 * @author JavaDroid
 * 
 */
public class ValidadorAmbienteIntegrado extends Observable{

	private String dicionario;
	private RegistroDeLog mensagemLog = RegistroDeLog.getInstance(ValidadorAmbienteIntegrado.class.getName());
	
	public boolean conexaoComOServidorDeRemessa() {
		boolean retorno = false;
		try {
			URL myURL = new URL(IndiceDeDados.ENDERECO_SERVIDOR_REMESSA.getValor());
		    URLConnection myURLConnection = myURL.openConnection();
		    myURLConnection.connect();
		    BufferedReader in = new BufferedReader(new InputStreamReader(myURLConnection.getInputStream()));
		    System.out.println(in.readLine());
		    in.close();
			retorno = true;
			mensagemLog.severe(IndiceDeDados.OK_SERVICO_REMESSA);
		}catch (ConnectException con) {
			mensagemLog.severe(IndiceDeDados.ERRO_CONN);
			mensagemLog.severe(con.getMessage());
		}catch (FileNotFoundException e) {
			mensagemLog.severe(IndiceDeDados.ERRO_FILE);
			mensagemLog.severe(e.getMessage());
		} catch (Exception e) {
			mensagemLog.severe(e.getMessage());
		}
		
		return retorno;
		} 

	public void updateObserver(String mensagem){
		setChanged();
		notifyObservers(mensagem);
	}
	
	
	public boolean downloadDosUltimosArquivosServidorDeAtualizacao(String arquivo) {
		boolean retorno = false;
		try {
			URL url = new URL(IndiceDeDados.ENDERECO_SERVIDOR_ATUALIZACAO.getValor() + arquivo);
			String destino = pastaTemporaria() + File.separatorChar + arquivo;
			InputStream is = url.openStream();
			FileOutputStream fos = new FileOutputStream(destino);
			int bytes = 0;
			while ((bytes = is.read()) != -1) {
				fos.write(bytes);
			}

			is.close();
			fos.close();
			System.gc();			
			retorno = validadorHash(new File(destino));
		} catch (MalformedURLException e) {
			mensagemLog.severe(IndiceDeDados.ERRO_URL);
			mensagemLog.severe(e.getLocalizedMessage());
		} catch (ConnectException e) {
			mensagemLog.severe(IndiceDeDados.ERRO_CONN);
			mensagemLog.severe(e.getMessage());
		} catch (IOException e) {
			mensagemLog.info(IndiceDeDados.ERRO_IO);
			mensagemLog.severe(e.getMessage());
		}
		return retorno;
	}
	
	public HashMap<String, String> buscaDicionarioDeDados() throws MalformedURLException, IOException{
		
		dicionario = new String(IndiceDeDados.ENDERECO_SERVIDOR_ATUALIZACAO.getValor() +IndiceDeDados.DICIONARIO.getValor());
		HashMap<String, String> mapa = new HashMap<String, String>();
		Scanner scanner = new Scanner(new URL(dicionario).openStream());
			while(scanner.hasNext()){
				mapa.put(scanner.next().split(" ")[0], scanner.nextLine().split(" ")[1]);
			}
			
		return mapa;
	}
	
	
	
	public boolean validadorHash(File file) {

		boolean retorno = false;
		String saida = null;
		try {
			MessageDigest digest = MessageDigest.getInstance("MD5");
			
			InputStream is = new FileInputStream(file);
			
			byte[] buffer = new byte[8192];
			int read = 0;

			while ((read = is.read(buffer)) > 0) {
				digest.update(buffer, 0, read);
			}
			byte[] md5sum = digest.digest();
			BigInteger bigint = new BigInteger(1, md5sum);
			saida = bigint.toString(16);
			HashMap<String, String> a = buscaDicionarioDeDados();
			if(a.containsKey(saida)){
				mensagemLog.info(IndiceDeDados.OK_ARQUIVO.getValor());
				mensagemLog.info(IndiceDeDados.OK_ARQUIVO);
				retorno = true;
			}else{
				mensagemLog.info(IndiceDeDados.ERRO_VALIDACAO_ARQUIVO.getValor() + file.getName());
				mensagemLog.info(IndiceDeDados.ERRO_VALIDACAO_ARQUIVO);
			}
			is.close();			
		} catch (NoSuchAlgorithmException e) {
			mensagemLog.severe(e.getMessage());
		} catch (FileNotFoundException e) {
			mensagemLog.severe(e.getMessage());
		} catch (IOException e) {
			mensagemLog.severe(e.getMessage());
		}
		return retorno;

	}
	
	
	public boolean verificandoArquivosParaHash(){
		File dir = new File(pastaTemporaria());
		boolean retorno = false;
		
		if(dir.list().length == 0){
			arquivosDoServidorDisponiveis();
		}
	
		for (File file : dir.listFiles()) {
			if(FilenameUtils.isExtension(file.getName(), "sic")){
				file.delete();
				if(dir.list().length == 0){
					return verificandoArquivosParaHash();
				}
			}
			if(FilenameUtils.isExtension(file.getName(), "jar")){
				retorno = validadorHash(file);
			}
		}
		
		return retorno;
	}

	public String pastaTemporaria() {
		File tempDir = new File(System.getProperty("java.io.tmpdir")+ IndiceDeDados.PASTA_TEMPORARIA.getValor());
		if (!tempDir.exists()) {
			mensagemLog.info(IndiceDeDados.OK_PASTATEMPORARIA.getValor());
			tempDir.mkdir();
		}
		return tempDir.getAbsolutePath();
	}

	public boolean arquivosDoServidorDisponiveis() {

		TreeMap<String, Date> mapDados = new TreeMap<String, Date>();
		boolean retorno = false; 
		try {
			URL url = new URL(IndiceDeDados.ENDERECO_SERVIDOR_ATUALIZACAO.getValor());
			URLConnection urlconnect = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(urlconnect.getInputStream()));
			String inputLine;

			DateFormat shortFormat = new SimpleDateFormat("dd-MM-yyyy",Locale.ENGLISH);
			DateFormat mediumFormat = new SimpleDateFormat("dd-MMM-yyyy",Locale.ENGLISH);
			
			int i = 0;
			while ((inputLine = in.readLine()) != null) {

				if (i > 7) {
					String[] rip = inputLine.replaceAll("<img.*?<a href=\"", "").replaceAll("\">.*?>", ";").split(";");
					if (rip.length > 1) {
						Date date = shortFormat.parse(shortFormat.format(mediumFormat.parse(rip[1].trim().substring(0, 11))));
						mapDados.put(rip[0], date);
					}
				}
				i++;
			}
			in.close();
			retorno = downloadUltimosArquivosPorData(mapDados);			
		} catch (MalformedURLException e) {
			mensagemLog.severe(IndiceDeDados.ERRO_URL);
			mensagemLog.severe(e.getMessage());
		}catch (ConnectException e) {
			mensagemLog.severe(IndiceDeDados.ERRO_CONN);
			mensagemLog.severe(e.getMessage());
		} catch (IOException e) {
			mensagemLog.severe(IndiceDeDados.ERRO_IO);
			mensagemLog.severe(e.getMessage());
		} catch (ParseException e) {
			mensagemLog.severe(e.getMessage());
		} catch (StringIndexOutOfBoundsException e) {
			mensagemLog.severe(e.getMessage());
		}
		return retorno;
	}

	
	public boolean downloadUltimosArquivosPorData(TreeMap<String, Date> map){
		
		boolean retorno = false;
		ValueComparator vlc = new ValueComparator(map);
		TreeMap<String, Date> mapaOrdenado = new TreeMap<String, Date>(vlc);
		mapaOrdenado.putAll(map);
		for (Entry<String, Date> string : mapaOrdenado.entrySet()) {
			if(mapaOrdenado.firstEntry().getValue().compareTo(string.getValue()) == 0){
				if(!(string.getKey().toString().equals("hashmd5.db"))){
					retorno = downloadDosUltimosArquivosServidorDeAtualizacao(string.getKey());
				}
			}
		}
		return retorno;
	}
	
	public void limparPastaTemporaria(){
		File dir = new File(pastaTemporaria());
			for (File arquivos : dir.listFiles()) {
				arquivos.delete();
			}
			mensagemLog.info(IndiceDeDados.OK_PASTATEMPORARIA_LIMPAR.getValor());
		}
	

	class ValueComparator implements Comparator<String> {

		Map<String, Date> base;

		public ValueComparator(Map<String, Date> base) {
			this.base = base;
		}
		public int compare(String a, String b) {
			if (base.get(a).after(base.get(b)) || base.get(a) == base.get(b)) {
				return -1;
			} else {
				return 1;
			} 
		}
	}
}
